
#include "ASprite.h"
#include <algorithm>
#include "Sprite_IDs.h"

//#include "Core/IApplication.h"
//#include "Entities/IFileStream.h"
//#include "IO/FileSystem/FileSystemBase.h"
//#include "Strings/StringManager.h"
#include <SMaterial.h>
#include <IVideoDriver.h>
#include <ITexture.h>
#include <irrString.h>
#include <IrrlichtDevice.h>
#include <ICameraSceneNode.h>
#include <ISceneManager.h>
#include "StringManager.h"
#include "../Graphic/IrrDevice.h"
#include "../Game.h"
#include "../System/NDSFile.h"
#include "../Predefine.h"
//#include "MenuUi/MenuUiCommon.h"


int	ASprite::_index1 = -1;
int	ASprite::_index2 = -1;
int ASprite::_text_w = 0;
int ASprite::_text_h = 0;
int ASprite::lines = 0;
int ASprite::off[MAX_LINES_PER_PAGE];


EXT_DRAW_INFO::EXT_DRAW_INFO()
{
	ROTATE_DEGREE = 0;
	ROTATE_CENTER_RATIO_X = 0.5f;
	ROTATE_CENTER_RATIO_Y = 0.5f;
	REF_X = REF_Y = 0;
	REF_POINT = ASprite::LEFT|ASprite::TOP;
	BRIGHT_SCALE = 1;
	BRIGHT_HALO = false;
	GRAY_EFFECT = false;
    BLEND_COLOR = video::SColor(255, 255, 255, 255);
}


ASprite::ASprite()
{
	_nModules = 0;
	_modules_x = NULL;
	_modules_y = NULL;
	_modules_w = NULL;
	_modules_h = NULL;
	_modules_img_index = NULL;
//	_modules_color = NULL;
//	_modules_type = NULL;

	_frames_nfm = NULL;
	_frames_fm_start = NULL;
	_frames_rc = NULL;
	_frames_col = NULL;

	nFModules = 0;
	_nFModules = NULL;
	_anims_naf = NULL;
	_anims_af_start = NULL;
	_aframes = NULL;
	bs_flags = 0;
	ex_bs_flags = 0;
	_modules_image = NULL;
	_nModulesImages = 0;
	//_char_spacing = 0;
	_line_spacing = 12;

	_map_char = NULL;

	_material = NULL;	
	indices[0] = 0;
	indices[1] = 2;
	indices[2] = 1;
	indices[3] = 0;
	indices[4] = 3;
	indices[5] = 2;

	vertices[0].Color = video::SColor(255, 255, 255, 255);
	vertices[1].Color = video::SColor(255, 255, 255, 255);
	vertices[2].Color = video::SColor(255, 255, 255, 255);
	vertices[3].Color = video::SColor(255, 255, 255, 255);

	_fmodules_correction = 0.0f;
	CreateMaterial();

	_isJPFont = false;
	_isARFont = false;
	_isKRFont = false;
	_isSRFont = false;
	_isFRFont = false;

	_isMallocMapChar = false;
}

ASprite::ASprite(int spriteId)
{
	_nModules = 0;
	_modules_x = NULL;
	_modules_y = NULL;
	_modules_w = NULL;
	_modules_h = NULL;
	_modules_img_index = NULL;
//	_modules_color = NULL;
//	_modules_type = NULL;

	_frames_nfm = NULL;
	_frames_fm_start = NULL;
	_frames_rc = NULL;
	_frames_col = NULL;

	nFModules = 0;
	_nFModules = NULL;
	_anims_naf = NULL;
	_anims_af_start = NULL;
	_aframes = NULL;
	bs_flags = 0;
	ex_bs_flags = 0;
	_modules_image = NULL;
	_nModulesImages = 0;
	//_char_spacing = 0;
	_line_spacing = 12;

	_map_char = NULL;

	_material = NULL;	
	indices[0] = 0;
	indices[1] = 2;
	indices[2] = 1;
	indices[3] = 0;
	indices[4] = 3;
	indices[5] = 2;

	vertices[0].Color = video::SColor(255, 255, 255, 255);
	vertices[1].Color = video::SColor(255, 255, 255, 255);
	vertices[2].Color = video::SColor(255, 255, 255, 255);
	vertices[3].Color = video::SColor(255, 255, 255, 255);

	_fmodules_correction = 0.0f;
	CreateMaterial();
    LoadSprite(spriteId);

	_isJPFont = false;
	_isARFont = false;
	_isKRFont = false;
	_isSRFont = false;
	_isFRFont = false;

	_isMallocMapChar = false;
}

ASprite::~ASprite()
{
	_nModules = 0;
	SAFE_DELETE(_modules_x);
	_modules_x = NULL;
	SAFE_DELETE(_modules_y);
	_modules_y = NULL;
	SAFE_DELETE(_modules_w);
	_modules_w = NULL;
	SAFE_DELETE(_modules_h);
	_modules_h = NULL;
	SAFE_DELETE(_modules_img_index);
	_modules_img_index = NULL;
	SAFE_DELETE(_modules_type);	
	SAFE_DELETE(_modules_color);
	

	SAFE_DELETE(_frames_nfm);
	_frames_nfm = NULL;
	SAFE_DELETE(_frames_fm_start);
	_frames_fm_start = NULL;
	SAFE_DELETE(_frames_rc);
	_frames_rc = NULL;
	SAFE_DELETE(_frames_col);
	_frames_col = NULL;

	nFModules = 0;
	SAFE_DELETE(_nFModules);
	_nFModules = NULL;
	SAFE_DELETE(_anims_naf);
	_anims_naf = NULL;
	SAFE_DELETE(_anims_af_start);
	_anims_af_start = NULL;
	SAFE_DELETE(_aframes);
	_aframes = NULL;
	
	SAFE_DELETE(_material);
	SAFE_DELETE(_material2d);
	if(_isMallocMapChar)
	{
		SAFE_DELETE_ARRAY(_map_char);
		_isMallocMapChar = false;
	}

	for(int i = 0; i < _nModulesImages; i++)
    {
		//TRACE("delete txt name = %s\r\n", _modules_image[i]->getName());
#if 0//mem_leak
        _modules_image[i]->drop();
#else
		CIrrDevice::GetVideoDriver()->removeTexture(_modules_image[i]);
#endif
    }
    SAFE_DELETE_ARRAY(_modules_image);
	_modules_image = NULL;
	//SafeDelete(_vertices);
}

void ASprite::LoadSprite(int spriteId)
{
    if(spriteId < PLAYER_SPRITES_BASE)
    {
        LoadSprite(SPRITES_NAMES[spriteId], SPRITES_TEXTURE_NAMES[spriteId]);
    }
    else
    {
//        LoadSprite(PLAYER_SPRITES_NAMES[spriteId - PLAYER_SPRITES_BASE], PLAYER_SPRITES_TEXTURE_NAMES[spriteId - PLAYER_SPRITES_BASE]);
    }
}

void ASprite::LoadSprite(const char* spriteName, const char* textureName)
{
	if(spriteName == NULL || textureName == NULL)
		return;

	CNDSFile file;

	BOOL bRet = file.Open(spriteName);
	if(!bRet)
	{
		return;
	}
	byte* rawData;


	rawData = NEW byte[(uint)file.GetFileSize()];
	StreamSize bytesRead = file.Read(rawData, file.GetFileSize());
	ASSERT(bytesRead == file.GetFileSize());

	file.Close();
	
	Load(rawData);

	SafeDeleteArray<byte>(rawData);

	//parse texture name cause it may contain more than one texture
	//textures are aepareted by ;
    irr::core::stringc str = textureName;
	s32 begin = 0, end;
	while((begin = str.findNext(';', begin)) != -1)
	{	
		begin++; //skip ; next time
		_nModulesImages++;
	}

	if(str.size() != begin)
		_nModulesImages++;

    _modules_image = NEW video::ITexture*[_nModulesImages]; 

	begin = 0;
	for(int i = 0; i < _nModulesImages; i++)
	{
		end = str.findNext(';', begin);
		if(end != -1)
		{
//			_modules_image[i] = IApplication::GetInstance()->GetDriver()->getTexture(str.subString(begin, end - begin));
			_modules_image[i] = CIrrDevice::GetVideoDriver()->getTexture(str.subString(begin, end - begin));
		}
		else
		{
//			_modules_image[i] = IApplication::GetInstance()->GetDriver()->getTexture(str.subString(begin, str.size() - begin));
			_modules_image[i] = CIrrDevice::GetVideoDriver()->getTexture(str.subString(begin, str.size() - begin));
		}
#if 0//mem_leak
        _modules_image[i]->grab();
#endif
		//_modules_image[i]->setMagFilter(ETFT_NEAREST);
		//_modules_image[i]->setMinFilter(ETFT_NEAREST);  
		begin = end + 1;
	}

}

// [2009-02-19 dongyi] DELETE this because it seems useless and may harm the reference-count system
//static map<std::pair<stringc, stringc>, ASprite*> spriteCache;
//
//ASprite* ASprite::LoadSpriteFromCache (int spriteId)
//{
//	return LoadSpriteFromCache(SPRITES_NAMES[spriteId], SPRITES_TEXTURE_NAMES[spriteId]);
//}
//
//ASprite* ASprite::LoadSpriteFromCache (const char* spriteName, const char* textureName)
//{
//	if (!spriteName || !textureName) return 0;
//
//	std::pair<stringc, stringc> key(spriteName, textureName);
//	map<std::pair<stringc, stringc>, ASprite*>::Node* node = spriteCache.find(key);
//	if (node) return node->getValue();
//
//	ASprite* sprite = NEW ASprite();
//	sprite->LoadSprite(spriteName, textureName);
//	spriteCache.insert(key, sprite);
//
//	return sprite;
//}
// [2009-02-19 dongyi]END


#define ReadByteFromRawData()	(rawdata[index] & 0xFF); index++
#define ReadShortFromRawData()	((rawdata[index] & 0xFF) | (rawdata[index+1] << 8)); index+=2
#define ReadIntFromRawData()	((rawdata[index] & 0xFF) | ((rawdata[index+1] & 0xFF) << 8) | ((rawdata[index+2] & 0xFF) << 16) | ((rawdata[index+3] & 0xFF) << 24)); index+=4
#define ReadFromRawData(dest, len)		memcpy(dest, (rawdata+index), len); index+=len

void ASprite::Load( byte* rawdata)
{

	int index = 0;
// 	TRACE("AURORA: File size = " + file.length + "; Offset = " + offset);
	short bs_version = ReadShortFromRawData();

// 	TRACE("AURORA: BSprite version = 0x" + Integer.toHexString(bs_version));

	if (bs_version != BSPRITE_v003 && bs_version != BSPRITE_v004 && bs_version != BSPRITE_v005) 
	{
// 		if (AURORA_DEBUG) TRACE("AURORA: ERROR - Invalid BSprite version!");
		return;
	}

	bs_flags = ReadIntFromRawData();

	if (bs_version == BSPRITE_v004)
	{
		ex_bs_flags = ReadIntFromRawData();
	}
	int MaxRectUsed = 0;

	// Modules
	if ((bs_flags & BS_MODULES) != 0) 
	{
		_nModules = ReadShortFromRawData();

// 		if (AURORA_DEBUG) TRACE("AURORA: nModules = " + _nModules);

		if (_nModules > 0)
		{
			_modules_x = NEW short[_nModules];
			_modules_y = NEW short[_nModules];
			_modules_w = NEW short[_nModules];
			_modules_h = NEW short[_nModules];
			_modules_img_index = NEW byte[_nModules];
			_modules_type = NEW char[_nModules];
			_modules_color = NEW unsigned int[_nModules];

			for (int i = 0; i < _nModules; i++)
			{
				byte mtype = ReadByteFromRawData();
 				if (mtype == 0xFF) // -> MD_RECT
 				{ 
 					if ((bs_flags & BS_MODULES_WH_SHORT)!=0)
						index += 8;
					else
						index += 6;
 				}
				else if (mtype == 0xFE) // -> MD_FILL_RECT
 				{ 
					_modules_type[i] = MD_FILL_RECT;
 					if ((bs_flags & BS_MODULES_WH_SHORT)!=0)
					{
						_modules_x[i] = 0;
						_modules_y[i] = 0;
						_modules_color[i] = ReadIntFromRawData();
						_modules_w[i] = ReadShortFromRawData();
						_modules_h[i] = ReadShortFromRawData();
					}
					else
						index += 6;
 				}
				else if (mtype == 0xFD) // -> MD_MARKER
 				{ 
 					if ((bs_flags & BS_MODULES_WH_SHORT)!=0)
						index += 4;
					else
						index += 2;
 				}
				else if (mtype == 0xFC) // -> MD_ARC
 				{ 
 					if ((bs_flags & BS_MODULES_WH_SHORT)!=0)
						index += 12;
					else
						index += 10;
 				}
 				else if (mtype == 0xFB) // -> MD_FILL_ARC
 				{ 
 					if ((bs_flags & BS_MODULES_WH_SHORT)!=0)
						index += 12;
					else
						index += 10;
 				}
				else if (mtype == 0xFA) // -> MD_TRIANGLE
 				{ 
					index += 12;
 				}
				else if (mtype == 0xF9) // -> MD_FILL_TRIANGLE
 				{ 
					index += 12;
 				}
 				else if (mtype == 0) // -> MD_IMAGE
				{
					_modules_type[i] = MD_IMAGE;
					if ((bs_flags & BS_MODULES_IMG)!=0)
					{
						_modules_img_index[i] = ReadByteFromRawData();	
					}

					if ((bs_flags & BS_MODULES_XY_SHORT)!=0)
					{
						_modules_x[i] = ReadShortFromRawData();
						_modules_y[i] = ReadShortFromRawData();
					}
 					else	if ((bs_flags & BS_MODULES_XY)!=0)
 					{
 						_modules_x[i] = (short)ReadByteFromRawData();
 						_modules_y[i] = (short)ReadByteFromRawData();
 					}
					
					if ((bs_flags & BS_MODULES_WH_SHORT)!=0)
					{
						_modules_w[i] = ReadShortFromRawData();
						_modules_h[i] = ReadShortFromRawData();
					}
					else
					{
						_modules_w[i] = (short)ReadByteFromRawData();
						_modules_h[i] = (short)ReadByteFromRawData();
					}
				}
			}
		}

		//3d stuff
		//_vertices = NEW video::S3DVertex[_nModules][4];
	}

	//FModules
	if ((bs_flags & BS_FRAMES) != 0) 
	{
		nFModules = ReadShortFromRawData();

// 		if (AURORA_DEBUG) TRACE("AURORA: nFModules = " + nFModules);

		if (nFModules > 0) 
		{
			int _nFModuleslength;
			int fm_module_length = 0;
			if ((bs_flags & BS_FM_OFF_SHORT) != 0) 
			{
				fm_module_length = 6;
			} 
			else 
			{
				fm_module_length = 4;
			}

			if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) != 0)
			{
				fm_module_length += 6;
			}

			_nFModuleslength = nFModules*fm_module_length;
			_nFModules = NEW int8[_nFModuleslength];

			ReadFromRawData(_nFModules,_nFModuleslength);

		}



		int nFrames = ReadShortFromRawData();
		_nFrames = nFrames;

// 		if (AURORA_DEBUG) TRACE("AURORA: nFrames = " + nFrames);

		if (nFrames > 0) 
		{
			short frame_rects_offset = 0;
			{		
				_frames_nfm = NEW short[nFrames];
				_frames_fm_start = NEW short[nFrames];
				for (int i = 0; i < nFrames; i++) 
				{
					if ((bs_flags & BS_NFM_1_BYTE) != 0)
					{
						_frames_nfm[i] = ReadByteFromRawData();
					}
					else
					{
						_frames_nfm[i] = ReadShortFromRawData();
					}

					_frames_fm_start[i] = ReadShortFromRawData();

					if ((bs_flags & BS_FRAME_RECTS) != 0) 
						index++;
				}
			}                                 
                                              
			if ((bs_flags & BS_SKIP_FRAME_RC) == 0) 
			{
				if ((bs_flags & BS_FM_OFF_SHORT) != 0) 
				{
					_frames_rc = NEW byte[nFrames<<3];
					ReadFromRawData(_frames_rc,nFrames<<3);
				}
				else
				{
					_frames_rc = NEW byte[nFrames<<2];
					ReadFromRawData(_frames_rc,nFrames<<2);
				}
			}                                 
                                              
			if ((bs_flags & BS_FRAME_COLL_RC) != 0) 
			{
				if ((bs_flags & BS_FM_OFF_SHORT) != 0)
				{
					_frames_col = NEW byte[nFrames<<3];
					ReadFromRawData(_frames_col,nFrames<<3);
				}
				else
				{
					_frames_col = NEW byte[nFrames<<2];
					ReadFromRawData(_frames_col,nFrames<<2);
				}
			}                                 
		}                                    
	}


	//AFrames
	if ((bs_flags & BS_ANIMS) != 0) 
	{
		_nAFrames = ReadShortFromRawData();

// 		if (AURORA_DEBUG) TRACE("AURORA: nAFrames = " + _nAFrames);

		if (_nAFrames > 0) 
		{
			int _nAFramesLength;
			if ((bs_flags & BS_AF_OFF_SHORT) != 0)
				_nAFramesLength = 7;
			else
				_nAFramesLength = 5;

			_aframes = NEW int8[_nAFrames*_nAFramesLength];

			ReadFromRawData(_aframes,_nAFrames*_nAFramesLength);
		}

		//Animsations

		int nAnims = ReadShortFromRawData();

		_nAnims = nAnims;
// 		if (AURORA_DEBUG) TRACE("AURORA: nAnims = " + nAnims);

		if (nAnims > 0) 
		{
			_anims_naf = NEW short[nAnims];
			_anims_af_start = NEW short[nAnims];
			for (int i = 0; i < nAnims; i++) 
			{
				if ((bs_flags & BS_NAF_1_BYTE) != 0)
				{
					_anims_naf[i] = ReadByteFromRawData();
				}
				else
				{
					_anims_naf[i] = ReadShortFromRawData();
				}

				_anims_af_start[i] = ReadShortFromRawData();
			}
		}
	}
}

void ASprite::PaintAFrame(int anim, int aframe, int posX, int posY, int flags, int hx, int hy , int alpha, int rotate, int xscale, int yscale, EXT_DRAW_INFO* info)
{
	int off = (_anims_af_start[anim] + aframe) * 5;
	int frame = _aframes[off] & 0xFF;

	if (USE_INDEX_EX_AFRAMES) {
		frame |= ((_aframes[off + 4] & FLAG_INDEX_EX_MASK) << INDEX_EX_SHIFT);
	}
	int temp_hx = _aframes[off + 2];
	int temp_hy = _aframes[off + 3];

	if (info == NULL)
	{
		if ((flags & FLAG_FLIP_X) != 0) hx += temp_hx;
		else hx -= temp_hx;
		if ((flags & FLAG_FLIP_Y) != 0) hy += temp_hy;
		else hy -= temp_hy;
	}
	else
	{
		info->REF_X += temp_hx;
		info->REF_Y += temp_hy;
	}
	PaintFrame( frame, posX - hx, posY - hy, flags ^ (_aframes[off + 4] & 0x0F), hx, hy,alpha, rotate,xscale,yscale,info);

}

void ASprite::PaintFModule( int frame, int fmodule, int posX, int posY, int flags, int hx, int hy,int alpha , int rotate,int xscale,int yscale ,EXT_DRAW_INFO* info )
{
	int off;
	int fm_flags;

	int ex_off = 0;
	if ((bs_flags & BS_FM_OFF_SHORT) != 0) 
	{
		if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) != 0)
			off = (_frames_fm_start[frame] + fmodule) * 12;
		else
			off = (_frames_fm_start[frame] + fmodule) * 6;
		fm_flags = _nFModules[off + 5] & 0xFF;
	} 
	else 
	{
		off = (_frames_fm_start[frame] + fmodule) << 2;
		fm_flags = _nFModules[off + 3] & 0xFF;
	}

	int index = _nFModules[off] & 0xFF;
	if (USE_INDEX_EX_FMODULES) 
	{
		index |= ((fm_flags & FLAG_INDEX_EX_MASK) << INDEX_EX_SHIFT);
	}

	//EXT_DRAW_INFO*	tempinfo = NULL;
	int temp_hx = (short)((_nFModules[off + 1] & 0xFF) + ((_nFModules[off + 2] & 0xFF) << 8));
	int temp_hy = (short)((_nFModules[off + 3] & 0xFF) + ((_nFModules[off + 4] & 0xFF) << 8));
	//if (info == NULL)
	{
		if ((flags & FLAG_FLIP_X) != 0) posX -= temp_hx;
		else posX += temp_hx;
		if ((flags & FLAG_FLIP_Y) != 0) posY -= temp_hy;
		else posY += temp_hy;
		
		if (USE_HYPER_FM && ((fm_flags & FLAG_HYPER_FM) != 0)) 
		{
			PaintFrame(index, posX, posY, flags ^ (fm_flags & 0x0F), hx, hy,alpha,rotate,xscale,yscale,info);
		} 
		else 
		{
			if ((flags & FLAG_FLIP_X) != 0) posX -= _modules_w[index]/* & 0xFF*/;
			if ((flags & FLAG_FLIP_Y) != 0) posY -= _modules_h[index]/* & 0xFF*/;

			if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) == 0)
				PaintModule(index, posX, posY, flags ^ (fm_flags & 0x0F),rotate,xscale,yscale,alpha,info);
			else
			{
				int	s_rotate = (short)((_nFModules[off + 6] & 0xFF) + ((_nFModules[off + 7] & 0xFF) << 8));
				int	s_xscale = (short)((_nFModules[off + 8] & 0xFF) + ((_nFModules[off + 9] & 0xFF) << 8));
				int	s_yscale = (short)((_nFModules[off + 10] & 0xFF) + ((_nFModules[off + 11] & 0xFF) << 8));
				PaintModule(index, posX, posY, flags ^ (fm_flags & 0x0F),s_rotate + rotate,s_xscale * xscale / 100,s_yscale * yscale / 100,alpha,info);
			}
		}
	}
	/*else
	{
 		EXT_DRAW_INFO	infocopy(*info);
		infocopy.REF_X += temp_hx;
		infocopy.REF_Y += temp_hy;
 		tempinfo = &infocopy;

		if (USE_HYPER_FM && ((fm_flags & FLAG_HYPER_FM) != 0)) 
		{
			PaintFrame(index, posX, posY, flags ^ (fm_flags & 0x0F), hx, hy,alpha,rotate,xscale,yscale,tempinfo);
		} 
		else 
		{
			if ((flags & FLAG_FLIP_X) != 0) posX -= _modules_w[index];
			if ((flags & FLAG_FLIP_Y) != 0) posY -= _modules_h[index];

			if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) == 0)
				PaintModule(index, posX, posY, flags ^ (fm_flags & 0x0F),rotate,xscale,yscale,alpha,tempinfo);
			else
			{
				int	s_rotate = (short)((_nFModules[off + 6] & 0xFF) + ((_nFModules[off + 7] & 0xFF) << 8));
				int	s_xscale = (short)((_nFModules[off + 8] & 0xFF) + ((_nFModules[off + 9] & 0xFF) << 8));
				int	s_yscale = (short)((_nFModules[off + 10] & 0xFF) + ((_nFModules[off + 11] & 0xFF) << 8));
				PaintModule(index, posX, posY, flags ^ (fm_flags & 0x0F),s_rotate + rotate,s_xscale * xscale / 100,s_yscale * yscale / 100,alpha,tempinfo);
			}
		}

	}*/

}

void ASprite::PaintModule(int module, int posX, int posY, int flags, int rotate, int xscale, int yscale,int alpha, EXT_DRAW_INFO* info)
{
	//if(module == 35)
	//{
	//	module = 35;
	//}

	if (_modules_type[module] ==  MD_FILL_RECT)
	{
		int srcPosX = _modules_x[module];
		int srcPosY = _modules_y[module];
		int sizeX = _modules_w[module];// & 0xFF;
		int sizeY = _modules_h[module];// & 0xFF;
		video::SColor color = _modules_color[module];
		color.A = 255;
//		color = video::SColor(255, 255, 255, 255);
		bool scale = false;

		if (sizeX <= 0 || sizeY <= 0)
			return;	

		core::rect<s32> destRect;
		destRect = core::rect<s32>(posX, posY, posX + sizeX, posY + sizeY);

		CIrrDevice::GetVideoDriver()->draw2DRectangle(color,destRect);
	//	CIrrDevice::GetVideoDriver()->draw2DImage(_modules_image[imgIndex], destRect, srcRect, &destRect, Scaled_Color, true);
	}

	if (_modules_type[module] ==  MD_IMAGE && _modules_image != NULL)
	{
		//A_ASSERT(module < _nModules);
		int srcPosX = _modules_x[module];
		int srcPosY = _modules_y[module];
		int sizeX = _modules_w[module];// & 0xFF;
		int sizeY = _modules_h[module];// & 0xFF;
		int imgIndex = _modules_img_index[module];
		int width = _modules_image[imgIndex]->getSize().Width;
		int height = _modules_image[imgIndex]->getSize().Height;
		bool scale = false;

		if (sizeX <= 0 || sizeY <= 0)
			return;



		if (_modules_image != NULL)
		{
			core::rect<s32> destRect;
			core::rect<s32> srcRect;
			core::rect<s32> clipRect;
			video::SColor color = video::SColor(alpha, 255, 255, 255);
			video::SColor Scaled_Color[4] =
			{
				color,
				color,
				color,
				color
			};

			matrix4 matrix,flipMatrix;

			//if ((flags & FLAG_ROT_90))
			//{
			//	matrix = CIrrDevice::GetVideoDriver()->getTransform(ETS_TEXTURE_0);
			//	flipMatrix = matrix;
			//	flipMatrix.setTextureRotationCenter(270 / 180.0 * PI);
			//	rect<s32> src(srcRect);
			//	srcPosX = height - _modules_y[module] - sizeY;
			//	srcPosY = _modules_x[module];
			//	sizeX = _modules_h[module];
			//	sizeY = _modules_w[module];

			//	CIrrDevice::GetVideoDriver()->setTransform(ETS_TEXTURE_0,flipMatrix);
			//}

			srcRect = core::rect<s32>(srcPosX, srcPosY, srcPosX + sizeX, srcPosY + sizeY);
		

			if (info == NULL)
				color = video::SColor(alpha, 255, 255, 255);
			else 
			{
				if(scale)
				{
					Scaled_Color[0] = info->BLEND_COLOR;
					Scaled_Color[1] = info->BLEND_COLOR;
					Scaled_Color[2] = info->BLEND_COLOR;
					Scaled_Color[3] = info->BLEND_COLOR;
				}
				else
				{
					color = video::SColor(alpha, 255, 255, 255);
					//color = info->BLEND_COLOR;
				}

			}

			//if(flags & FLAG_ROT_90)
			//{
			//	int i = 0;
			//	i++;
			//}

			if (flags & FLAG_FLIP_X && flags & FLAG_FLIP_Y)
			{
				srcRect = core::rect<s32>(srcPosX + sizeX, srcPosY + sizeY, srcPosX, srcPosY);			
			}
			else if (flags & FLAG_FLIP_X)
			{
				//if(flags & FLAG_ROT_90)
				//{
				//	srcRect = core::rect<s32>(srcPosX, srcPosY + sizeY, srcPosX + sizeX, srcPosY);									
				//}
				//else
				{
					srcRect = core::rect<s32>(srcPosX + sizeX, srcPosY, srcPosX, srcPosY + sizeY);
				}

			}
			else if (flags & FLAG_FLIP_Y)
			{
				//if(flags & FLAG_ROT_90)
				//{
				//	srcRect = core::rect<s32>(srcPosX + sizeX, srcPosY, srcPosX, srcPosY + sizeY);
				//}
				//else
				{
					srcRect = core::rect<s32>(srcPosX, srcPosY + sizeY, srcPosX + sizeX, srcPosY);				
				}
			}
			//else
			{
				/*srcRect.UpperLeftCorner.X += 1;
				srcRect.UpperLeftCorner.Y += 1;
				srcRect.LowerRightCorner.X += 1;
				srcRect.LowerRightCorner.Y += 1;*/
			}


			if(xscale != 100 || yscale != 100)
			{
				int newSizeX = sizeX*xscale/100;
				int newSizeY = sizeY*yscale/100;
				posX -= ((newSizeX - sizeX)>>1);
				posY -= ((newSizeY - sizeY)>>1);
				sizeX = newSizeX;
				sizeY = newSizeY;
				scale = true;
			}

			core::position2d<s32> pos(posX, posY);
			destRect = core::rect<s32>(posX, posY, posX + sizeX, posY + sizeY);
			//destRect = core::rect<s32>(posX + sizeX, posY + sizeY, posX, posY);


			core::rect<s32> poss(pos, core::abs(srcRect.getSize()));
			SColor colorsArray[4] = {color, color, color, color };
#ifndef IPHONEOS
			//if(flags & FLAG_FLIP_X)
			//{		
			//	srcRect.UpperLeftCorner.X -= 1;
			//	srcRect.UpperLeftCorner.Y += 1;
			//}
			//else
			//{
			//	srcRect.UpperLeftCorner.X += 1;
			//	srcRect.UpperLeftCorner.Y += 1;
			//}
#endif
			
			
			if(_modules_image[imgIndex])
			{
				const core::dimension2d<s32>& size = _modules_image[imgIndex]->getOriginalSize();
				const f32 invW = 1.f / static_cast<f32>(size.Width);
				const f32 invH = 1.f / static_cast<f32>(size.Height);
				core::rect<f32> tcoords((f32)srcRect.UpperLeftCorner.X * invW, (f32)srcRect.UpperLeftCorner.Y * invH, (f32)srcRect.LowerRightCorner.X * invW, (f32)srcRect.LowerRightCorner.Y * invH);


				video::S3DVertex vertices[4];
				vertices[0].Pos = core::vector3df(destRect.LowerRightCorner.X,destRect.LowerRightCorner.Y,0);
				vertices[1].Pos = core::vector3df(destRect.LowerRightCorner.X,destRect.UpperLeftCorner.Y,0);
				vertices[2].Pos = core::vector3df(destRect.UpperLeftCorner.X,destRect.UpperLeftCorner.Y,0);
				vertices[3].Pos = core::vector3df(destRect.UpperLeftCorner.X,destRect.LowerRightCorner.Y,0);

				if(flags & FLAG_ROT_90)
				{
					destRect = core::rect<s32>(posX, posY, posX + sizeY, posY + sizeX);

					vertices[1].Pos = core::vector3df(destRect.LowerRightCorner.X,destRect.LowerRightCorner.Y,0);
					vertices[2].Pos = core::vector3df(destRect.LowerRightCorner.X,destRect.UpperLeftCorner.Y,0);
					vertices[3].Pos = core::vector3df(destRect.UpperLeftCorner.X,destRect.UpperLeftCorner.Y,0);
					vertices[0].Pos = core::vector3df(destRect.UpperLeftCorner.X,destRect.LowerRightCorner.Y,0);
				}

				if(info != NULL && info->ROTATE_DEGREE != 0)
				{
					vector3df center(destRect.UpperLeftCorner.X + destRect.getWidth() * info->ROTATE_CENTER_RATIO_X, destRect.UpperLeftCorner.Y + destRect.getHeight() * info->ROTATE_CENTER_RATIO_Y, 0);
					vertices[0].Pos.rotateXYBy(info->ROTATE_DEGREE,center);
					vertices[1].Pos.rotateXYBy(info->ROTATE_DEGREE,center);
					vertices[2].Pos.rotateXYBy(info->ROTATE_DEGREE,center);
					vertices[3].Pos.rotateXYBy(info->ROTATE_DEGREE,center);
				}
				vertices[0].TCoords.set(tcoords.LowerRightCorner.X,tcoords.LowerRightCorner.Y);
				vertices[1].TCoords.set(tcoords.LowerRightCorner.X,tcoords.UpperLeftCorner.Y);
				vertices[2].TCoords.set(tcoords.UpperLeftCorner.X, tcoords.UpperLeftCorner.Y);
				vertices[3].TCoords.set(tcoords.UpperLeftCorner.X, tcoords.LowerRightCorner.Y);
				vertices[0].Color = color;
				vertices[1].Color = color;
				vertices[2].Color = color;
				vertices[3].Color = color;

				u16 indicess[] = { 0, 2, 1, 0, 3, 2 };
				
				
				CIrrDevice::GetVideoDriver()->set2DTexture(_modules_image[imgIndex],true);
				_material2d->setTexture(0, _modules_image[imgIndex]);
				CIrrDevice::GetVideoDriver()->set2DMaterial(*_material2d);
				CIrrDevice::GetVideoDriver()->drawVertexPrimitiveList(vertices, indicess, 0, 4, 2, irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES, irr::video::EIT_16BIT);


			}
			//CIrrDevice::GetVideoDriver()->draw2DImage(_modules_image[imgIndex], destRect, srcRect, &destRect, Scaled_Color, true);
			if (flags & FLAG_ROT_90)
			{			
				CIrrDevice::GetVideoDriver()->setTransform(ETS_TEXTURE_0,matrix);
			}
		}

	}
}

int ASprite::mapKRChr(unsigned short krchr)
{
	unsigned short chr;
	chr = krchr;

	const unsigned short* _map_KR_char = (const unsigned short*)_map_char;

	int start = 0;
	int end = _map_char_cnt - 1;

	if(chr==0x00e7)
	{
		return 151;
	}
	if(chr==0x00f1)
	{
		return 161;
	}

	while (start < end)
	{
		if (end - start == 1)
		{
			if (_map_KR_char[start] == chr)
				return start;
			else if (_map_KR_char[end] == chr)
				return end;
			else
			{
				//ASSERT(krchr == '|' || krchr == 1 || krchr == 2);
				return -1;
			}
		}

		int cp = (start + end) >> 1;

		if (_map_KR_char[cp] == chr)
			return cp;

		if (_map_KR_char[cp] > chr)
			end = cp;
		else	// if (JP_chr_map[cp] < chr)
			start = cp;
	}

	ASSERT(false);

	return 0;
}

int ASprite::mapSRChr(unsigned short srchr)
{
	unsigned short chr;
	chr = srchr;

	const unsigned short* _map_SR_char = (const unsigned short*)_map_char;

	int start = 0;
	int end = _map_char_cnt - 1;

	while (start < end)
	{
		if (end - start == 1)
		{
			if (_map_SR_char[start] == chr)
				return start;
			else if (_map_SR_char[end] == chr)
				return end;
			else
			{
				//ASSERT(srchr == '|' || srchr == 1 || srchr == 2);
				return -1;
			}
		}

		int cp = (start + end) >> 1;

		if (_map_SR_char[cp] == chr)
			return cp;

		if (_map_SR_char[cp] > chr)
			end = cp;
		else
			start = cp;
	}

	ASSERT(false);

	return 0;
}

int ASprite::mapJPChr(unsigned short jpchr)
{
	unsigned short chr;
	chr = jpchr;

	const unsigned short* _map_JP_char = (const unsigned short*)_map_char;

	int start = 0;
	int end = _map_char_cnt - 1;

	while (start < end)
	{
		if (end - start == 1)
		{
			if (_map_JP_char[start] == chr)
				return start;
			else if (_map_JP_char[end] == chr)
				return end;
			else
			{
				//ASSERT(jpchr == '|' || jpchr == 1 || jpchr == 2);
				return -1;
			}
		}

		int cp = (start + end) >> 1;

		if (_map_JP_char[cp] == chr)
			return cp;

		if (_map_JP_char[cp] > chr)
			end = cp;
		else
			start = cp;
	}

	ASSERT(false);

	return 0;
}

int ASprite::mapARChr(unsigned short archr)
{
	if (archr >= 0x0600 && archr <= 0x06ff)
		return archr - 0x0600;
	if (archr >= 0xfe70 && archr <= 0xfeff)
		return archr - 0xfe70 + 257;
	if (archr == 0xa9) //copyright character
		return 0x100;
	if (archr >= L'0' && archr <= L'9')
		return archr + 350;
	if (archr >= L'A' && archr <= L'Z')
		return archr + 343;
	if (archr >= L'a' && archr <= L'z')
		return archr - ('a'-'A') + 343;
	if (archr == L'!')
		return 434;
	if (archr == L'?')
		return 435;
	if (archr == L'.')
		return 436;
	if (archr == L':')
		return 437;
	if (archr == 0x00c7)
		return 438;
	if (archr == 0x00d1)
		return 439;
	if (archr == L'@')
		return 440;
	if (archr == L'-')
		return 441;
	if (archr == L'/')
		return 442;
	if (archr == L'\"')
		return 443;

	return archr;
}

////////////////////////////////////////////////////////////////////////////////////////////////////

// NOTE : If you set interpretNewLine at True, this will change global height and probably scrap  
//        all draw text that using this variable.
//		  So, if you only want to get string width, don't enable this parameter.

int ASprite::GetStringSize(TChar* s, int index1, int index2, bool interpretSpecialChar, bool interpretNewLine)
{	
	const int spacing = GetFModuleOffX(0);
	
	int tw = 0;
	index1 = (index1 >= 0 ? index1 : 0);
	//index2 = (index2 >= 0 ? index2 : (_isJPFont || _isARFont ? wcslen((wchar_t*)s) : strlen(s)));
	index2 = (index2 >= 0 ? index2 : wcslen(s));
	
	for (int i = index1; i < index2; i++)
	{
		int c, m, c1 = -1;
		bool isKR = false;

		if (_isJPFont || _isARFont || _isKRFont || _isSRFont)
		{
			c = ((wchar_t*)s)[i] & 0xFFFF;
			if(_isSRFont)
			{
				c1 = ((wchar_t*)s)[i + 1] & 0xFFFF;
			}
			else
			{
				if(i + 1 < index2)
					c1 = ((wchar_t*)s)[i + 1] & 0xFFFF;
			}
		}
		else
		{
			c = s[i] & 0xFF;
			if(i + 1 < index2)
				c1 = s[i + 1] & 0xFF;
		}

		//Map lowercase to Upper.
		if(!_isJPFont && !_isKRFont && !_isSRFont)
		{
			if(c >= 97 && c <= 122)
			{
				c -= 32;
			}

			ChangeLowercaseAccentCharToUpper(c);

			//Change fr accent char to normal char. 
			ChangeFRAccentCharToNormal(c);
		}

		//added bu le.liu2 for korean language select bug
		if(s[i]==-61&&i+1<index2&&s[i+1]==-89)//france
		{
			c = 231;
			i+=1;
		}
		if(s[i]==-61&&i+1<index2&&s[i+1]==-79)//e
		{
			c = 241;
			i+=1;
		}
		if(s[i]==-127&&i+1<index2&&s[i+1]==95&&i+2<index2&&s[i+2]==120)//e
		{
			c=4;
			i=index2-1;
		}
		
		
		if (c == '^') // (^)(char)(Text)
		{
			i++;
			if(interpretSpecialChar)
				InterpretStringSpecialChar(_isJPFont || _isARFont? ((wchar_t*)s)[i]/*s[i << 1]*/ : s[i]);
			continue;
		}
		else if (c == ' ')
		{
			FontAddSpace(tw, spacing);
			continue;
		}
		else if (c == '\n')
		{
			if( interpretNewLine )
			{
				if (tw > _text_w) _text_w = tw;
				tw = 0;
				//_text_h += _line_spacing + (_modules_h[0]&0xFF);
			}
			continue;
		}
		else if(c == '\\' && c1 == '0' || c == '\\' && c1 == '1')
		{
			i++;
			continue;
		}
		else if (_isJPFont)
		{
			c = mapJPChr(c);
			m = c;
		}
		else if (_isKRFont)
		{
			c = mapKRChr(c);
			m = c;
		}
		else if(_isSRFont)
		{
			c = mapSRChr(c);
			m = c;
		}
		else if (_isARFont)
		{
			c = mapARChr(c);
			if( c >= 0x4B && c <= 0x55)
			{
				continue;
			}
			int off = (_frames_fm_start[0]+c);
			int fm_flags = _nFModules[off + 5] & 0xFF;
			m = _nFModules[off * s_font_fm_module_length] & 0xFF;
			if (USE_INDEX_EX_FMODULES)
				m |= ((fm_flags&FLAG_INDEX_EX_MASK)<<INDEX_EX_SHIFT);
		}
		else
		{
			if(c == '_')
			{
				if(!CGame::GetGame()->m_pStringManager->IsAsianLanguage())
				{
					FontAddSpace(tw, spacing);
					continue;
				}
			}
			c = _map_char[c]&0xFF;
			m = _nFModules[c * s_font_fm_module_length] & 0xFF;
		}
		
		if (c != -1 && m != -1)
			tw += (_modules_w[m]&0xFFFF) + GetFModuleOffX(c) + spacing;	
	}
	return tw;
}

void ASprite::FontAddSpace(int & tw, int spacing)
{
	if(_isKRFont || _isSRFont || _isJPFont)
	{
		tw += 11;//space width
	}
	else
	{
		tw += (_modules_w[0]&0xFFFF) + spacing;
	}
}

void ASprite::UpdateStringSize(TChar* ws, bool interpretSpecialChar/* = false*/)
{
	//char* s = (char*)ws;
	const int spacing = GetFModuleOffX(0);

	_text_w = 0;
	_text_h = (_modules_h[0]&0xFF);
	
	int index1 = ((_index1 >= 0) ? _index1 : 0);
	//int index2 = ((_index2 >= 0) ? _index2 : (_isJPFont || _isARFont? wcslen((wchar_t*)s) : strlen(s)));
	int index2 = ((_index2 >= 0) ? _index2 : wcslen(ws));
	int tw = GetStringSize(ws, index1, index2, interpretSpecialChar, true);
	if (tw > _text_w) _text_w = tw;
	if (_text_w > 0) _text_w -= spacing;
}

//int ASprite::UpdateStringSize(TChar* s)
//{
//	_text_w = 0;
//	_text_h = _line_height;
//	int tw = 0;
//	int tmpEscapeDigit = CGame::GetGame()->m_pStringManager->GetCurrentEscapeDigit();
//
//	int index1 = ((_index1 >= 0) ? _index1 : 0);
//	int index2 = ((_index2 >= 0) ? _index2 : StrLength(s));
//
//	int prev_c = -1;
//	for (int i = index1; i < index2; i++) 
//	{
//		TChar c = s[i] & 0xFFFF; 
//
//		if(c == ESCAPE_CHARACTER_PREFIX)
//		{
//			TChar nextChar = s[++i];
//
//			TChar* str1 = CGame::GetGame()->m_pStringManager->GetSpecialCharacterString(nextChar);
//			tw += UpdateStringSize(str1);
//			continue;
//		}
//
//		tw += GetCharacterWidth(c) + _char_spacing;
//	}
//
//	if (tw > _text_w)
//		_text_w = tw;
//
//	CGame::GetGame()->m_pStringManager->SetCurrentEscapeDigit(tmpEscapeDigit);
//
//	return tw;
//}

void ASprite::InterpretStringSpecialChar(char specialChar)
{		
	// 0 to 9 ==> switch to palette 0 to 9 (if possible)...
	if(specialChar >= '0' && specialChar <= '9')
	{
		int palette = specialChar - '0';
		_crt_pal = palette;
	}
	else if(specialChar == 'H') //highlight start
	{
		
	}
	else if(specialChar == 'h') //highlight end
	{
		
	}
}

void ASprite::DrawString( TChar* ws, int x, int y, int anchor ,int color , int alpha ,int rotate , int x_scale , int y_scale , bool WB , bool WH, int roateAngle)
{
	TChar* s = ws;

	int oldX = x;

	const int spacing = GetFModuleOffX(0);

	if ((anchor & (RIGHT | HCENTER | BOTTOM | VCENTER)) != 0)
	{
		UpdateStringSize(ws, false);
		if ((anchor & RIGHT)   != 0)	x -= _text_w;
		else if ((anchor & HCENTER) != 0)	x -= _text_w>>1;
		if ((anchor & BOTTOM)  != 0)	y -= _text_h;
		else if ((anchor & VCENTER) != 0)	y -= _text_h>>1;
	}

	if(_isKRFont || _isSRFont || _isJPFont)
	{
		y -= 18;
	}
	else
	{
		y -= (18 + 5);
	}

	//if (scale256 != 256)
	//	g->SetScale(scale256, x + (_text_w >> 1), y + (_text_h >> 1));

	int xx = x;
	int yy = y;

	int old_pal = _crt_pal;

	int index1 = ((_index1 >= 0) ? _index1 : 0);
	int index2 = wcslen(ws);
	index2 = ((_index2 >= 0) ? _index2 : index2);



	for (int i = index1; i < index2; i++)
	{		
		int c, m, c1 = -1, c2 = -1, cw = -1;
		bool isKR = false;

		if (_isJPFont || _isARFont || _isKRFont || _isSRFont)//le.liu2 for Korean
		{
			c = ((wchar_t*)s)[i] & 0xFFFF;
			if(i + 1 < index2)
				c1 = ((wchar_t*)s)[i + 1] & 0xFFFF;
		}
		else
		{
			//Specal char
			cw = s[i] & 0xFFFF;
			if(cw == 8482)
			{
				c = 253;
			}
			else
			{
				c = s[i] & 0xFF;
				if(i + 1 < index2)
					c1 = s[i + 1] & 0xFF;
			}
		}

		//Map lowercase to Upper.
		if(!_isJPFont && !_isKRFont && !_isSRFont)
		{
			if(c >= 97 && c <= 122)
			{
				c -= 32;
			}

			ChangeLowercaseAccentCharToUpper(c);

			//Change fr accent char to normal char. 
			ChangeFRAccentCharToNormal(c);
		}

		//added bu le.liu2 for korean language select bug
		if(s[i]==-61&&i+1<index2&&s[i+1]==-89)//france
		{
			c = 231;
			i+=1;
		}
		else if(s[i]==-61&&i+1<index2&&s[i+1]==-79)//e
		{
			c = 241;
			i+=1;
		}
		else if(s[i]==-127&&i+1<index2&&s[i+1]==95&&i+2<index2&&s[i+2]==120)//Arabic
		{
			c=4;
			i=index2-1;
		}
		if (c == '^') // (^)(char)(Text)
		{
			i++;
			InterpretStringSpecialChar(_isJPFont || _isARFont ? ((wchar_t*)s)[i]/*s[i << 1]*/ : s[i]);
			continue;
		}
		else if (c == ' ')
		{
			FontAddSpace(xx, spacing);
			continue;
		}
		else if (c == '\n')
		{	
			xx = oldX;
			yy += _line_spacing + (_modules_h[0]&0xFF);
			if ((anchor & (RIGHT | HCENTER | BOTTOM | VCENTER)) != 0)
			{
				int subStringLen = GetSubStringWidth(ws, i + 1, index2);
				if ((anchor & RIGHT)   != 0)	xx -= subStringLen;
				else if ((anchor & HCENTER) != 0)	xx -= subStringLen>>1;
				//if ((anchor & BOTTOM)  != 0)	yy -= _text_h;
				//else if ((anchor & VCENTER) != 0)	yy -= _text_h>>1;
			}

			continue;
		}
		else if(c == '|')
		{
			continue;
		}
		else if(c == '\\' && c1 == '0' || c == '\\' && c1 == '1')
		{
			i++;
			continue;
		}
		else if (_isJPFont)
		{
			c = mapJPChr(c);
			m = c;
		}
		else if (_isKRFont)
		{
			c = mapKRChr(c);
			m = c;
		}
		else if (_isSRFont)
		{
			c = mapSRChr(c);
			m = c;
		}
		else if (_isARFont)
		{
			c = mapARChr(c);

			if( c >= 0x4B && c <= 0x55)
			{
				_arabicAccent = c;
				continue;
			}
			int off = (_frames_fm_start[0]+c);
			int fm_flags = _nFModules[off + 5] & 0xFF;
			m = _nFModules[off * s_font_fm_module_length] & 0xFF;
			if(m==237)
			{
				m=237;
			}
			if (USE_INDEX_EX_FMODULES)
				m |= ((fm_flags&FLAG_INDEX_EX_MASK)<<INDEX_EX_SHIFT);
		}
		else
		{
			if(c == '_')
			{
				if(!CGame::GetGame()->m_pStringManager->IsAsianLanguage())
				{
					FontAddSpace(xx, spacing);
					continue;
				}
			}
			c = _map_char[c]&0xFF;
			m = _nFModules[c * s_font_fm_module_length] & 0xFF;
		}

		if (c != -1 && m != -1)
		{
			if(c == 383)
			{
				c = 383;
			}
			if(roateAngle != 0)
			{
				EXT_DRAW_INFO info;
				info.ROTATE_DEGREE = roateAngle;
				int rotatedX = xx;
				int rotatedY = yy;
				GetStringRotateY(x, y, rotatedX, rotatedY, roateAngle);
				PaintFModule(0, c, rotatedX, rotatedY, 0, 0, 0, alpha, 0, 100, 100, &info);
			}
			else
			{
				PaintFModule(0, c, xx, yy, 0, 0, 0, alpha);
			}
			if(_arabicAccent != -1)
			{
				PaintFModule(0, _arabicAccent, xx, yy, 0, 0, 0, alpha);
				_arabicAccent = -1;
			}
			xx += (_modules_w[m]&0xFFFF) + GetFModuleOffX(c) + spacing; 
		}
	}

	//if (scale256 != 256)
	//	g->SetScale();

	_crt_pal = old_pal;
}

//Change fr accent char to normal char. 
void ASprite::ChangeFRAccentCharToNormal(int& c)
{
	//FModule index in sprite
	if(_isFRFont)
	{
		if(c == 194 || c == 192)//A
		{
			c = 65;
		}
		else if(c == 200 || c == 201 || c == 203 || c == 202)//E
		{
			c = 69;
		}
		else if(c == 206 || c == 207)//I
		{
			c = 73;
		}
		else if(c == 212)//O
		{
			c = 79;
		}
		else if(c == 217 || c == 218 || c == 219)//U
		{
			c = 85;
		}
		else if(c == 199 || c == 231)//C
		{
			c = 67;
		}
	}
}

void ASprite::ChangeLowercaseAccentCharToUpper(int& c)
{
	switch(c)
	{
	case 225:
		c = 193;
		break;
	case 224:
		c = 192;
		break;
	case 226:
		c = 194;
		break;
	case 228:
		c = 196;
		break;
	case 227:
		c = 195;
		break;
	case 232:
		c = 200;
		break;
	case 233:
		c = 201;
		break;
	case 234:
		c = 202;
		break;
	case 235:
		c = 203;
		break;
	case 236:
		c = 204;
		break;
	case 237:
		c = 205;
		break;
	case 238:
		c = 206;
		break;
	case 239:
		c = 207;
		break;
	case 242:
		c = 210;
		break;
	case 243:
		c = 211;
		break;
	case 244:
		c = 212;
		break;
	case 246:
		c = 214;
		break;
	case 245:
		c = 213;
		break;
	case 249:
		c = 217;
		break;
	case 250:
		c = 218;
		break;
	case 251:
		c = 219;
		break;
	case 252:
		c = 220;
		break;
	case 241:
		c = 209;
		break;
	}
}

void ASprite::GetStringRotateY(int basePointX, int basePointY, int& currX, int& currY, int rotateAngle)
{
	vector3df center(basePointX, basePointY, 0);
	video::S3DVertex verticeChar;
	verticeChar.Pos = core::vector3df(currX, currY, 0);
	verticeChar.Pos.rotateXYBy((f64)rotateAngle,center);
	currX = verticeChar.Pos.X;
	currY = verticeChar.Pos.Y;
}

int ASprite::FindWordEnd(wchar_t* text, int startOffset)
{
	int text_length = wcslen(text);
	if( startOffset >= text_length)
		return -1;

	while(startOffset < text_length)
	{
		if(text[startOffset] == ' ' || text[startOffset] == '\n' || text[startOffset] == '|')
			return startOffset-1;

		startOffset++;
	}

	return text_length - 1;
}

int ASprite::WrapText(TChar* text, int maxWidth)
{
    return WrapText(text, maxWidth, true);
}

int ASprite::WrapText(TChar* orgtext, int maxWidth, bool unwrap)
{
	const int spacing = GetFModuleOffX(0);

	TChar* text = orgtext;
	//if (_isJPFont)
	//{
		//strexpand((const unsigned char*)text, STRLEN(text), m_pGame->wcsbuffer, WCSBUFFERSIZE * sizeof(wchar_t));
		//text = (char*)m_pGame->wcsbuffer;
	//}

	//int text_length = (_isJPFont || _isARFont ? wcslen((wchar_t*)text) : STRLEN(text));
	int text_length = wcslen(text);

	if( unwrap )
	{
		if (_isJPFont)
			UnwrapText((wchar_t*)text);
		else
			UnwrapText(text);
	}
	int wordEnd, wordWidth;
	int lineWidth = 0;
	int numLine   = 1;
	
    int currentIndex = 0;

	bool foundArabChar = false;
	int firstArabIndex = -1;

    while( currentIndex < text_length || _isARFont)
    {
        int c;
		int isKRindex = 0;
		bool isKR = false;
	
		if (_isJPFont || _isARFont || _isKRFont || _isSRFont)
			c = ((wchar_t*)text)[currentIndex] & 0xFFFF;	// (((text[currentIndex << 1] & 0xFF) << 8) + (text[(currentIndex << 1) + 1] & 0xFF)) & 0xFFFF;
		else
			c = text[currentIndex] & 0xFF;

		if (c >= 0x0600 && c <= 0x06ff ||
			c >= 0xfe70 && c <= 0xfeff ||
			c == L' ' || c == L'!' ||
			c == L'^' || (c >= L'0' && c <= L'9') ||
			c == L'%' || c == L'/' || c == L'.' || c == L'-' ||/*
			(c == L'i' && currentIndex > 0 && ((wchar_t*)text)[currentIndex-1] == L'%') ||
			(c == L's' && currentIndex > 0 && ((wchar_t*)text)[currentIndex-1] == L'%') ||
			(c == L'j' && currentIndex > 0 && ((wchar_t*)text)[currentIndex-1] == L'%') ||
			(c == L'W' && currentIndex > 0 && ((wchar_t*)text)[currentIndex-1] == L'%') ||
			(c == L'L' && currentIndex > 0 && ((wchar_t*)text)[currentIndex-1] == L'%') ||*/
			c == L's'
			)
		{
			if (firstArabIndex == -1)
				firstArabIndex = currentIndex;
			if (c >= 0x0600 && c <= 0x06ff ||
				c >= 0xfe70 && c <= 0xfeff)
				foundArabChar = true;
		}
		else
		{
			if (foundArabChar)
			{
				numLine += WrapTextArabic(&(((wchar_t*)text)[firstArabIndex]), currentIndex-firstArabIndex, maxWidth, &lineWidth);
				foundArabChar = false;
			}
			firstArabIndex = -1;
		}

		if (currentIndex >= text_length)
			break;
		
		if( c == '\n')
        {
			lineWidth = 0;
			if(currentIndex != 0)
			{
				++numLine;
			}

			if(isKR)
			{
				 currentIndex+=isKRindex;     //  skip newline char
			}else{
				currentIndex++;     //  skip newline char
			}
        }
        else
        {
			if (!_isARFont && !_isSRFont)
			{
				if( c == ' ')
				{
					//  we assume that spaces can't fit a whole line
					FontAddSpace(lineWidth, spacing);
					if(isKR)
					{
						currentIndex+=isKRindex;     //  skip newline char
					}else{
						currentIndex++;     //  skip newline char
					}
					//currentIndex++;     //  skip space char
					continue;
				}
				else if (c == '|')
				{
					if(isKR)
					{
						currentIndex+=isKRindex;     //  skip newline char
					}else{
						currentIndex++;     //  skip newline char
					}
					//currentIndex++;     //  skip space char
					continue;
				}
				if (_isJPFont)
				{
					wordEnd = FindWordEnd((wchar_t*)text, currentIndex);
					wordWidth = GetSubStringWidth((wchar_t*)text, currentIndex, wordEnd);
				}
				else
				{
					wordEnd = FindWordEnd(text, currentIndex);
					wordWidth = GetSubStringWidth(text, currentIndex, wordEnd);
				}
				if( wordEnd == text_length - 1)	//	do not add letter spacing at end of text
				{
					wordWidth -= GetFModuleOffX(0);
				}

				lineWidth += wordWidth;
				if(lineWidth > maxWidth)
				{
					if(currentIndex > 0)	//	can't wrap on first word...
					{
						if (_isJPFont || _isKRFont)
							((wchar_t*)text)[currentIndex - 1] = '\n';
						else
							text[currentIndex - 1] = '\n';
						lineWidth = wordWidth;
						++numLine;
					}
				}
				currentIndex = wordEnd + 1;     //  skip word
			}
			else if(_isARFont)
			{
				if(!foundArabChar && (c == L' ' || c == L'!' ||
					    (c >= L'0' && c <= L'9') ||
					    c == L'/' || c == L'.' || c == L'-' || c == '\"'))
				{	
					
					c = mapARChr(c);
					if( c >= 0x4B && c <= 0x55)
					{
						continue;
					}
					int off = (_frames_fm_start[0]+c);
					int fm_flags = GetFModuleFlags(off);
					int m = GetFModuleIndex(off);
					if (USE_INDEX_EX_FMODULES)
						m |= ((fm_flags&FLAG_INDEX_EX_MASK)<<INDEX_EX_SHIFT);
					
					if (c != -1 && m != -1)
						lineWidth += (_modules_w[m]&0xFFFF) + GetFModuleOffX(c) + GetFModuleOffX(0);
				}
				else if(!foundArabChar)
				{
					ASSERT(c == 0x5e);
				}
				if(isKR)
				{
					currentIndex+=isKRindex;     //  skip newline char
				}else{
					currentIndex++;     //  skip newline char
				}
				//currentIndex++;
			}
			else if(_isSRFont)
			{
				int nNextIndex = 0;

				if(IsSRFontPunctuation(((wchar_t*)text)[currentIndex + 1] & 0xFFFF))
				{
					nNextIndex = currentIndex + 2;
				}
				else
				{
					nNextIndex = currentIndex + 1;
				}
				wordWidth = GetStringSize(text, currentIndex, nNextIndex, false, false);
				lineWidth += wordWidth;
				if(lineWidth > maxWidth)
				{
					if(currentIndex > 0)	//	can't wrap on first word...
					{
						lineWidth = 0;
						++numLine;
						continue;
					}
				}
				if(IsSRFontPunctuation(((wchar_t*)text)[currentIndex + 1] & 0xFFFF))
				{
					currentIndex += 2;
				}
				else
				{
					++currentIndex;
				}
			}
        }
    }

	//if (_isJPFont)
	//	wstrcompress((wchar_t*)text, wcslen((wchar_t*)text), (u8*)orgtext, STRLEN(orgtext));
	return numLine;
}

bool ASprite::IsSRFontPunctuation(int c)
{
	if( c == 0x21
		|| c == 0x22
		|| c == 0x26
		|| c == 0x27
		|| c == 0x2C
		|| c == 0x2D
		|| c == 0x2E
		|| c == 0x2F
		|| c == 0x3B
		|| c == 0x3C
		|| c == 0x3D
		|| c == 0x3E
		|| c == 0x3F
		|| c == 0x40
		|| c == 0x5C
		|| c == 0x5F
		|| c == 0xA9
		|| c == 0x201C
		|| c == 0x201D
		|| c == 0x2122
		|| c == 0x3002
		|| c == 0xFF01
		|| c == 0xFF0C
		|| c == 0xFF0D
		|| c == 0xFF1A
		|| c == 0xFF1F )
	{
		return true;
	}
	return false;
}

//return end indez.
int ASprite::GetSubStringIndex(wchar_t* text, int startIndex, int maxWidth)
{
	int text_length = wcslen(text);

	int wordWidth;
	int lineWidth = 0;
	
    int currentIndex = startIndex;

    while(currentIndex < text_length)
    {
        int c;
		c = ((wchar_t*)text)[currentIndex] & 0xFFFF;

		if (currentIndex >= text_length)
			break;
		
		if (c == '\n')
		{
			return currentIndex;
		}

		int nNextIndex = 0;
		if(IsSRFontPunctuation(((wchar_t*)text)[currentIndex + 1] & 0xFFFF))
		{
			nNextIndex = currentIndex + 2;
		}
		else
		{
			nNextIndex = currentIndex + 1;
		}
		wordWidth = GetStringSize(text, currentIndex, nNextIndex, false, false);
		lineWidth += wordWidth;
		if(lineWidth > maxWidth)
		{
			return currentIndex - 1;
		}
		if(IsSRFontPunctuation(((wchar_t*)text)[currentIndex + 1] & 0xFFFF))
		{
			currentIndex += 2;
		}
		else
		{
			++currentIndex;
		}
    }
	return currentIndex;
}

int ASprite::GetSubStringWidth(wchar_t* text, int startIndex, int endIndex)
{
	int i1 = _index1;
	int i2 = _index2;
	int tw = _text_w;
	int width = 0;

	SetSubString(startIndex, endIndex == -1 ? -1 : endIndex+1);	// Modify by FengCheng [11/10/2007]
	//UpdateStringSize((char*)text, true);
	{
		const int spacing = GetFModuleOffX(0);

		_text_w = 0;
		_text_h = (_modules_h[0]&0xFF);
	
		//int index1 = ((_index1 >= 0) ? _index1 : 0);
		//int index2 = ((_index2 >= 0) ? _index2 : (_isJPFont || _isARFont? WSTRLEN((wchar_t*)s) : STRLEN(s)));

		//int tw = GetStringSize((char*)text, _index1, _index2, true, true);
		int tw = GetStringSize(text, _index1, _index2, true, true);
		if (tw > _text_w) _text_w = tw;
		if (_text_w > 0) _text_w -= spacing;

	}
	width = _text_w;
	_index1 = i1;
	_index2 = i2;
	_text_w = tw;

	const int spacing = GetFModuleOffX(0);

	width += spacing;
	return width;
}

int ASprite::WrapTextArabic(wchar_t* text, int length, int maxWidth, int *cWidth)
{
	/*
	length = 29;
	text = new wchar_t[29];
	WSTRCPY(text,L"ABCDE FGHIJK LMNOPQ RSTUVWXYZ");
	maxWidth = 70;
	*/

	int index = length-1;
	int endWordIndex;
	//int *cWidth = currentWidth;
	wchar_t tmp[512];
	int retVal = 0;
	int leftLimit = 0;
	while (index >= leftLimit)
	{
		endWordIndex = index;
		while (text[endWordIndex] != ' ' && endWordIndex >= 0 && text[endWordIndex] != '\n')
			endWordIndex--;
//		if (endWordIndex >= leftLimit)
		{
			//if (endWordIndex >= 0 && text[endWordIndex] == '\n')
			//{
			//	index = endWordIndex-1;
			//	*cWidth= 0;
			//	length = index + 1;
			//	if (index < 0)
			//		break;
			//}
			//else
			{
				*cWidth += GetSubStringWidth(text, endWordIndex+1, index);
				if (*cWidth > maxWidth && index < length-1)
				{
						memcpy(tmp,&text[index+2],(length-index-2)*sizeof(wchar_t));
						memcpy(&text[leftLimit+length-index-1],&text[leftLimit],(index-leftLimit+1)*sizeof(wchar_t));
						memcpy(&text[leftLimit],tmp,(length-index-2)*sizeof(wchar_t));
						text[leftLimit+length-index-2] = L'\n';
						leftLimit += length-index-1;
						*cWidth = 0;
						index = length-1;
						retVal++;
				}
				else
				{
					if (endWordIndex >= 0 && text[endWordIndex] == '\n')
					{
						index = endWordIndex-1;
						*cWidth= 0;
						length = index + 1;
						if (index < 0)
							break;
					}
					else if (text[endWordIndex] == L' ')
						*cWidth += _modules_w[0];
					index = endWordIndex-1;
				}
			}
		}
		/*
		else
		{
			break;
		}
		*/
	}
	return retVal;
}

void ASprite::UnwrapText(wchar_t* text)
{
	if (_isJPFont)
	{
		for(int i = 0; i < (int)wcslen(text); ++i)
		{
			if(text[i] == '\n')
				text[i] = '|';
		}
	}
}

int ASprite::DrawPage( TChar* s, int x, int y, int width, int start, int line_number, int character_number, int anchor, int type, bool bUpdate ,int color, bool WB, bool bDrawString, bool unwrap)
{
	WrapText(s, width, unwrap);

	// Count lines...
	int lines = 0;
	int len = wcslen(s);
    int off[100];
    memset(off, 0, 100*sizeof(int));
	
	int th = _line_spacing + (_modules_h[0]&0xFF);// - 4;

	int textHeight = 0;

	if(_isSRFont)
	{
		int startIndex = 0;
		while(startIndex < len)
		{
			off[lines++] = GetSubStringIndex(s, startIndex, width) + 1;
			startIndex = off[lines - 1];
		}
		for (int i = 0; i < len; i++)
		{
			if (s[i] == '\n' && i != 0)
			{
				textHeight += th;
			}
		}
	}
	else
	{
		for (int i = 0; i < len; i++)
		{
			if (s[i] == '\n' && i != 0)
			{
				off[lines++] = i;
				textHeight += th;
			}
		}
		off[lines++] = len;
	}

	if ((anchor & BOTTOM)  != 0)	y -= textHeight;
	else if ((anchor & VCENTER) != 0)	y -= (textHeight >> 1);

	//return count lines num;
	if(!bDrawString)
	{
		return lines;
	}

	// Draw each line...
	for (int j = start; j < (start + line_number > lines ? lines : start + line_number); j++) 
	{
		if(_isSRFont)
			_index1 = (j > 0) ? off[j-1] : 0;
		else
			_index1 = (j > 0) ? off[j-1]+1 : 0;
		_index2 = off[j];
		DrawString(s, x, y, anchor, false);
		y += th;
	}
	// Disable substring...
	_index1 = -1;
	_index2 = -1;
	return (start + line_number > lines ? lines : start + line_number);
}

int ASprite::GetFontFrameWidth(int frame)
{
    if(GetFrameColWidth(frame) == 0)
    {
        return GetFrameWidth(frame);
    }
    else
    {
        return GetFrameColWidth(frame);
    }
}

int ASprite::GetFontFrameLeft(int frame)
{
    int a = GetFrameColLeft(frame);
    return GetFrameColLeft(frame);
}

int ASprite::GetFModuleOffX(int frame, int fmodule)
{
	int off;

	int ex_off = 0;
	if ((bs_flags & BS_FM_OFF_SHORT) != 0) 
	{
		if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) != 0)
			off = (_frames_fm_start[frame] + fmodule) * 12;
		else
			off = (_frames_fm_start[frame] + fmodule) * 6;
	} 
	else 
	{
		off = (_frames_fm_start[frame] + fmodule) << 2;
	}

	return ((_nFModules[off + 1] & 0xFF) + ((_nFModules[off + 2] & 0xFF) << 8));
}

int ASprite::GetFModuleOffY(int frame, int fmodule)
{
	int off;

	int ex_off = 0;
	if ((bs_flags & BS_FM_OFF_SHORT) != 0) 
	{
		if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) != 0)
			off = (_frames_fm_start[frame] + fmodule) * 12;
		else
			off = (_frames_fm_start[frame] + fmodule) * 6;
	} 
	else 
	{
		off = (_frames_fm_start[frame] + fmodule) << 2;
	}

	return ((_nFModules[off + 3] & 0xFF) + ((_nFModules[off + 4] & 0xFF) << 8));
}

int ASprite::GetFModuleIndex(int off)
{
	off *= s_font_fm_module_length;
	return ((_nFModules[off] & 0xFF));
}

int ASprite::GetFModuleOffX(int off)
{
	off *= s_font_fm_module_length;
	return ((_nFModules[off + 1] & 0xFF) + ((_nFModules[off + 2] & 0xFF) << 8));
}

int ASprite::GetFModuleOffY(int off)
{
	off *= s_font_fm_module_length;
	return ((_nFModules[off + 3] & 0xFF) + ((_nFModules[off + 4] & 0xFF) << 8));
}

int ASprite::GetFModuleFlags(int off)
{
	off *= s_font_fm_module_length;
	return ((_nFModules[off + 5] & 0xFF));
}

void ASprite::SetCharacterMap(unsigned short* pMapChar)
{
	_map_char = pMapChar;
}

void ASprite::LoadCharacterMap()
{
	if(_map_char == null)
	{
		//this should be enough for europen languages
		_map_char = NEW unsigned short[256];
		memset(_map_char, 0, sizeof(unsigned short)*256);
		_isMallocMapChar = true;
	}

	for (int i = 32; i < 256; ++i)
	{
		_map_char[i] = (short) i;
	}
}

void ASprite::FreeMapChar(int language)
{
	if(_isMallocMapChar && 
		(LANGUAGE_KR == language || LANGUAGE_JP == language || LANGUAGE_SR == language))
	{
		SAFE_DELETE_ARRAY(_map_char);
		_isMallocMapChar = false;
	}
}


int ASprite::GetCharFrame(TChar c)
{
	if (c < 0)
	{
		c = (c & 0xFFFF);
	}
	
	if( c < 0 || c >= 65535)
	{			
		c = ' ';
	}
	
	ASSERT( _map_char[c] >= 0 );
	
	if(_map_char[c] < 0 )
	{			
		c = '?';
	}
	return _map_char[c];
}

int ASprite::GetCharacterWidth(TChar c)
{
	//Special cases character.
	if(c == '\n')
	{
		return 0;
	}
	
	int frame = GetCharFrame(c);
	return GetFrameWidth(frame);
}

int ASprite::StrLength(TChar* s)
{
	//int index = 0;
	//while(s[index] !=0) index++;
	//return index;
	
	return wcslen(s);
}


void ASprite::NearestImage()
{
	_modules_image[0]->setMagFilter(ETFT_NEAREST);
	_modules_image[0]->setMinFilter(ETFT_NEAREST);
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Paint 3D
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
void ASprite::CreateMaterial()
{
    _material = NEW video::SMaterial();
	_material->setFlag(irr::video::EMF_LIGHTING, false);		
	_material->setMaterialType(irr::video::EMT_TRANSPARENT_ALPHA_CHANNEL);
	_material->setFlag(irr::video::EMF_BACK_FACE_CULLING, false);
	_material->setFlag(irr::video::EMF_ZBUFFER, true);
	_material->setFlag(irr::video::EMF_ZWRITE_ENABLE, true);
	_material->setFlag(irr::video::EMF_2D_USE_TEXTURE_ALPHA, true);
	
	_material2d = NEW video::SMaterial();
	_material2d->setFlag(irr::video::EMF_ZWRITE_ENABLE, true);
	_material2d->setFlag(irr::video::EMF_2D_USE_TEXTURE_ALPHA, true);
	_material2d->setFlag(irr::video::EMF_2D_USE_VERTEX_ALPHA, true);
}

void ASprite::SetMaterialType(irr::video::E_MATERIAL_TYPE type)
{
	_material2d->setMaterialType(type);
}

/*
void ASprite::PaintAnimation3D(int anim, const irr::core::vector3df& pos, int flags, bool loop,bool isFaceCamera, irr::f32 xscale, irr::f32 yscale)
{
	int currentTime = irr::os::Timer::getTime();

	if (0 == m_animationFramePlayTime[anim])
		m_animationFramePlayTime[anim] = currentTime;

	int animTime = GetAFrameTime(anim, m_animationCurrentFrameIndex[anim]);
	if (currentTime - m_animationFramePlayTime[anim] >= animTime * 1000 / 30)
	{
		m_animationFramePlayTime[anim] = currentTime;
		m_animationCurrentFrameIndex[anim]++;
		if (m_animationCurrentFrameIndex[anim] >= GetAFrames(anim))
		{
			if (loop)
				m_animationCurrentFrameIndex[anim] = 0;
			else
				m_animationCurrentFrameIndex[anim] = GetAFrames(anim) - 1;
		}
	}

	PaintAFrame3D(anim, m_animationCurrentFrameIndex[anim], pos, flags,isFaceCamera, xscale, yscale);
}
*/

void ASprite::PaintAFrame3D(int anim, int aframe, const irr::core::vector3df& pos, int flags,bool isFaceCamera, irr::f32 xscale, irr::f32 yscale)
{
	if (!_anims_af_start) return;

	int off = (_anims_af_start[anim] + aframe) * 5;
	int frame = _aframes[off] & 0xFF;

	if (USE_INDEX_EX_AFRAMES) {
		frame |= ((_aframes[off + 4] & FLAG_INDEX_EX_MASK) << INDEX_EX_SHIFT);
	}
	int temp_hx = _aframes[off + 2];
	int temp_hy = _aframes[off + 3];

	int hx = 0, hy = 0;

	if ((flags & FLAG_FLIP_X) != 0) hx += temp_hx;
	else hx -= temp_hx;
	if ((flags & FLAG_FLIP_Y) != 0) hy += temp_hy;
	else hy -= temp_hy;
	
	PaintFrame3D( frame, pos, flags ^ (_aframes[off + 4] & 0x0F),isFaceCamera, hx, hy, xscale, yscale);
}

void ASprite::PaintFrame3D(int frame, const irr::core::vector3df& pos, int flags,bool isFaceCamera, int hx, int hy, irr::f32 xscale, irr::f32 yscale)
{
	int nFModules = _frames_nfm[frame]&0xFF;

	for (int fmodule = 0; fmodule < nFModules; fmodule++)
	{
		PaintFModule3D(frame, fmodule, pos, flags,isFaceCamera, hx, hy, xscale, yscale);
		_fmodules_correction += 0.005f;
	}
	_fmodules_correction = 0.0f;
}

void ASprite::PaintFModule3D(int frame, int fmodule, const irr::core::vector3df& pos, int flags,bool isFaceCamera, int hx, int hy, irr::f32 xscale, irr::f32 yscale)
{
	int off;
	int fm_flags;

	int ex_off = 0;
	if ((bs_flags & BS_FM_OFF_SHORT) != 0) 
	{
		if ((ex_bs_flags & BS_FM_FREE_ROTATE_SCALE) != 0)
			off = (_frames_fm_start[frame] + fmodule) * 12;
		else
			off = (_frames_fm_start[frame] + fmodule) * 6;
		fm_flags = _nFModules[off + 5] & 0xFF;
	} 
	else 
	{
		off = (_frames_fm_start[frame] + fmodule) << 2;
		fm_flags = _nFModules[off + 3] & 0xFF;
	}

	int index = _nFModules[off] & 0xFF;
	if (USE_INDEX_EX_FMODULES) 
	{
		index |= ((fm_flags & FLAG_INDEX_EX_MASK) << INDEX_EX_SHIFT);
	}
	int temp_hx = (short)((_nFModules[off + 1] & 0xFF) + ((_nFModules[off + 2] & 0xFF) << 8));
	int temp_hy = (short)((_nFModules[off + 3] & 0xFF) + ((_nFModules[off + 4] & 0xFF) << 8));

	if ((flags & FLAG_FLIP_X) != 0) 
		hx += temp_hx;
	else 
		hx -= temp_hx;
	if ((flags & FLAG_FLIP_Y) != 0) 
		hy += temp_hy;
	else 
		hy -= temp_hy;
	
	if (USE_HYPER_FM && ((fm_flags & FLAG_HYPER_FM) != 0)) 
	{
		PaintFrame3D(index, pos, flags ^ (fm_flags & 0x0F), isFaceCamera,hx, hy, xscale, yscale);
	} 
	else 
	{
		PaintModule3D(index, pos, flags ^ (fm_flags & 0x0F),isFaceCamera, hx, hy, xscale, yscale);
	}
}


void ASprite::PaintModule3D(int module, const irr::core::vector3df& pos, int flags,bool isFaceCamera, int hx, int hy, irr::f32 xscale, irr::f32 yscale)
{
	int srcPosX = _modules_x[module];
	int srcPosY = _modules_y[module];
	int sizeX = _modules_w[module];
	int sizeY = _modules_h[module];

	if (sizeX <= 0 || sizeY <= 0)
		return;

	irr::IrrlichtDevice* pDevice = CIrrDevice::GetIrrlichtDevice();
	irr::video::IVideoDriver* driver = pDevice->getVideoDriver();

	irr::scene::ISceneManager* smgr = pDevice->getSceneManager();
	irr::scene::ICameraSceneNode* camera = smgr->getActiveCamera();

	hx -= (sizeX>>1);
	hy -= (sizeY>>1);

	irr::core::vector3df campos = irr::core::vector3df(0.0,0.0,0.0);
	irr::core::vector3df target = pos;
	if( isFaceCamera )
	{
		campos = camera->getAbsolutePosition();
		target = camera->getTarget();
	}
	irr::core::vector3df up = camera->getUpVector();
	irr::core::vector3df view = target - campos;
	view.normalize();

	irr::core::vector3df offset;
	offset -= _fmodules_correction*view;

	irr::core::vector3df horizontal = up.crossProduct(view);
	if ( horizontal.getLength() == 0 )
	{
		horizontal.set(up.Y,up.X,up.Z);
	}
	horizontal.normalize();
	offset -= horizontal*xscale*((irr::f32)hx);
	horizontal *= 0.5f*sizeX*xscale;

	irr::core::vector3df vertical = horizontal.crossProduct(view);
	vertical.normalize();
	offset -= vertical*yscale*((irr::f32)hy);
	vertical *= 0.5f*sizeY*yscale;

	view *= -1.0f;

	for (irr::s32 i=0; i<4; ++i)
		vertices[i].Normal = view;

	vertices[0].Pos = pos + horizontal + vertical + offset;
	vertices[1].Pos = pos + horizontal - vertical + offset;
	vertices[2].Pos = pos - horizontal - vertical + offset;
	vertices[3].Pos = pos - horizontal + vertical + offset;

	irr::core::dimension2d<irr::s32> size = _modules_image[0]->getSize();
	const irr::f32 invW = 1.f / static_cast<irr::f32>(size.Width);
	const irr::f32 invH = 1.f / static_cast<irr::f32>(size.Height);

	//use 1- for native texture
	//vertices[0].TCoords.set((srcPosX + sizeX)*invW, 1-(srcPosY + sizeY)*invH);
	//vertices[1].TCoords.set((srcPosX + sizeX)*invW, 1-srcPosY*invH);
	//vertices[2].TCoords.set(srcPosX*invW, 1-srcPosY*invH);
	//vertices[3].TCoords.set(srcPosX*invW, 1-(srcPosY + sizeY)*invH);
	
	//Note: fix uv problem on new irr engine (wh,2009-7-14)
	vertices[0].TCoords.set((srcPosX + sizeX)*invW, (srcPosY + sizeY)*invH);
	vertices[1].TCoords.set((srcPosX + sizeX)*invW, srcPosY*invH);
	vertices[2].TCoords.set(srcPosX*invW, srcPosY*invH);
	vertices[3].TCoords.set(srcPosX*invW, (srcPosY + sizeY)*invH);
	

	if ((flags & FLAG_FLIP_X))
	{
		std::swap(vertices[0].TCoords, vertices[3].TCoords);
		std::swap(vertices[1].TCoords, vertices[2].TCoords);
	}
	if ((flags & FLAG_FLIP_Y))
	{
		std::swap(vertices[0].TCoords, vertices[1].TCoords);
		std::swap(vertices[2].TCoords, vertices[3].TCoords);
	}
	
	// set identity matrix
	driver->setTransform(irr::video::ETS_WORLD, irr::core::matrix4());
	_material->setTexture(0, _modules_image[0]);
	driver->setMaterial(*_material);
	driver->drawVertexPrimitiveList(vertices, indices, 0, 4, 2, irr::video::EVT_STANDARD, irr::scene::EPT_TRIANGLES, irr::video::EIT_16BIT);	
}

void ASprite::SetVertexColor(const irr::video::SColor& color)
{
	vertices[0].Color = color;
	vertices[1].Color = color;
	vertices[2].Color = color;
	vertices[3].Color = color;
}

void ASprite::SetEscapeCharacter(CEscapeCharacter * EscapeChar)
{
	m_pEscapeChar = EscapeChar;
}
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////////////////

